package com.scorpio.common.utils.treenode;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 树形工具
 */
public class TreeNodeUtil {

    private static final HashMap<String, List<Field>> Fields = new HashMap<>();


    /**
     * 编译树形
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<T> bulid(List<T> list) {
        return bulid(list, null, Integer.MAX_VALUE);
    }

    /**
     * 编译树形
     *
     * @param list
     * @param startParentId 起始的父ID
     * @param <T>
     * @return
     */
    public static <T> List<T> bulid(List<T> list, Object startParentId) {
        return bulid(list, startParentId, Integer.MAX_VALUE);
    }

    /**
     * 编译树形
     *
     * @param list
     * @param startParentId 起始的父ID
     * @param maxLevel      最大编译阶级
     * @param <T>
     * @return
     */
    public static <T> List<T> bulid(List<T> list, Object startParentId, int maxLevel) {
        List<T> resultList = new ArrayList<>();
        if (list.size() > 0) {
            Class entityClass = list.get(0).getClass();
            Map<Object, List<T>> map = new HashMap<>();
            for (T item : list) {
                Object praentId = getParameter(entityClass, item, TreeNodeType.ParentId);
                if ((praentId == null && startParentId != null) || (praentId != null && startParentId == null)) {
                    continue;
                }
                if ((praentId == null && startParentId == null) || praentId.equals(startParentId)) {
                    resultList.add(item);
                } else {
                    setCacheMap(map, praentId, item);
                }
            }
            for (T item : resultList) {
                Object id = getParameter(entityClass, item, TreeNodeType.ID);
                setChildren(map, entityClass, id, item, 1, maxLevel);
            }
        }
        return resultList;
    }


    /**
     * 设置子列表
     *
     * @param map
     * @param entityClass
     * @param id
     * @param entity
     * @param thisLevel
     * @param maxLevel
     * @param <T>
     */
    private static <T> void setChildren(Map<Object, List<T>> map, Class entityClass, Object id, T entity, int thisLevel, int maxLevel) {
        if (thisLevel < maxLevel) {
            List<T> list = map.get(id);
            if (list != null) {
                for (T item : list) {
                    Object idd = getParameter(entityClass, item, TreeNodeType.ID);
                    setChildren(map, entityClass, idd, item, thisLevel + 1, maxLevel);
                }
            } else {
                list = new ArrayList<>();
            }
            setParameter(entityClass, entity, list, TreeNodeType.Children);
        }
    }


    /**
     * 设置缓存
     *
     * @param map
     * @param key
     * @param entity
     * @param <T>
     * @return
     */
    private static <T> List<T> setCacheMap(Map<Object, List<T>> map, Object key, T entity) {
        List<T> clist = map.get(key);
        if (clist == null) {
            clist = new ArrayList<>();
            map.put(key, clist);
        }
        if (entity != null) clist.add(entity);
        return clist;
    }


    /**
     * 获取参数
     *
     * @param aClass   实体所属类
     * @param entity   实体
     * @param nodeType 参数类型
     * @param <T>
     * @return
     */
    private static <T> Object getParameter(Class aClass, T entity, TreeNodeType nodeType) {
        Field field = getParameterField(aClass, nodeType);
        try {
            return field.get(entity);
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * 设置参数
     *
     * @param aClass   实体所属类
     * @param entity   实体
     * @param obj      设置的参数
     * @param nodeType 参数类型
     * @param <T>
     */
    private static <T> void setParameter(Class aClass, T entity, Object obj, TreeNodeType nodeType) {
        Field field = getParameterField(aClass, nodeType);
        try {
            field.set(entity, obj);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //获取变量反射实体
    private static <T> Field getParameterField(Class aClass, TreeNodeType nodeType) {
        List<Field> fields = getField(aClass);
        for (Field field : fields) {
            TreeNode treeNode = field.getAnnotation(TreeNode.class);
            if (treeNode.value() == nodeType) {
                return field;
            }
        }
        return null;
    }

    //从缓存中获取反射的变量
    private static List<Field> getField(Class aClass) {
        List<Field> fields = Fields.get(aClass.getName());
        if (fields == null) {
            fields = new ArrayList<>();
            Field[] checkFields = aClass.getDeclaredFields();
            for (int i = checkFields.length - 1; i >= 0; i--) {
                if (checkFields[i].isAnnotationPresent(TreeNode.class)) {
                    checkFields[i].setAccessible(true);
                    fields.add(checkFields[i]);
                }
            }
            Fields.put(aClass.getName(), fields);
        }
        return fields;
    }

}
